home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / languages / obrn-a_1.5_lib.lha / oberon-a / source2.lha / Source / Library / Files.mod < prev    next >
Encoding:
Text File  |  1995-01-26  |  16.1 KB  |  716 lines

  1. (*************************************************************************
  2.  
  3.      $RCSfile: Files.mod $
  4.   Description: Operations on files and the file directory.
  5.  
  6.    Created by: fjc (Frank Copeland)
  7.     $Revision: 1.11 $
  8.       $Author: fjc $
  9.         $Date: 1995/01/26 00:40:27 $
  10.  
  11.   Copyright © 1994-1995, Frank Copeland.
  12.   This file is part of the Oberon-A Library.
  13.   See Oberon-A.doc for conditions of use and distribution.
  14.  
  15. *************************************************************************)
  16.  
  17. <* STANDARD- *> <* MAIN- *>
  18. <*$ LongVars+ *> <*$ NilChk- *> <*$ IndexChk- *>
  19.  
  20. MODULE Files;
  21.  
  22. IMPORT
  23.   SYS := SYSTEM, Kernel, e := Exec, d := Dos, du := DosUtil,
  24.   str := Strings, conv := Conversions, o := Oberon;
  25.  
  26. CONST
  27.   SectorSize = 1024;
  28.   MaxBufs = 4;
  29.  
  30. TYPE
  31.  
  32.   File *= POINTER TO Handle;
  33.  
  34.   Buffer = POINTER TO BufferRecord;
  35.  
  36.   Rider *= RECORD
  37.     eof -: BOOLEAN;
  38.     res -: LONGINT;
  39.     file : File;
  40.     pos : LONGINT;
  41.     buf : Buffer;
  42.     bpos : INTEGER;
  43.   END; (* Rider *)
  44.  
  45.   Handle = RECORD
  46.     fl -: d.FileLockPtr;
  47.     fh -: d.FileHandlePtr;
  48.     name : ARRAY 256 OF CHAR;
  49.     tempNo : LONGINT;
  50.     pos, len : LONGINT;
  51.     useCount, nofbufs : INTEGER;
  52.     next : File;
  53.     firstbuf : Buffer;
  54.   END; (* Handle *)
  55.  
  56.   DataSector = ARRAY SectorSize OF SYS.BYTE;
  57.  
  58.   BufferRecord = RECORD
  59.     apos : LONGINT;
  60.     lim : INTEGER;
  61.     mod : BOOLEAN;
  62.     next : Buffer;
  63.     data : DataSector;
  64.   END; (* BufferRecord *)
  65.  
  66.  
  67. VAR
  68.   root : File;
  69.   tempNo : LONGINT;
  70.  
  71. CONST
  72.   tempExt = ".tmp";
  73.   bkpExt = ".bkp";
  74.  
  75.  
  76. PROCEDURE GetTempNo;
  77.  
  78.   VAR time, date : LONGINT;
  79.  
  80. BEGIN (* GetTempNo *)
  81.   o.GetClock (time, date);
  82.   tempNo := ABS ((date * 10000H + time) DIV 2)
  83. END GetTempNo;
  84.  
  85.  
  86. PROCEDURE MakeName
  87.   ( name : ARRAY OF CHAR;
  88.     tempNo : LONGINT;
  89.     ext : ARRAY OF CHAR;
  90.     VAR tempName : ARRAY OF CHAR );
  91.  
  92.   VAR pathPart : e.LSTRPTR; s : ARRAY 13 OF CHAR;
  93.  
  94. <*$CopyArrays-*>
  95. BEGIN (* MakeName *)
  96.   COPY (name, tempName);
  97.   IF tempName # "" THEN
  98.     pathPart := d.PathPart (tempName); pathPart [0] := 0X
  99.   END;
  100.   ASSERT (conv.IntToStr (tempNo, 16, 0, "0", s));
  101.   str.Append (ext, s);
  102.   ASSERT (d.AddPart (tempName, s, LEN (tempName)))
  103. END MakeName;
  104.  
  105.  
  106. PROCEDURE Search ( fl : d.FileLockPtr ) : File;
  107.  
  108.   VAR f : File;
  109.  
  110. BEGIN (* Search *)
  111.   f := root;
  112.   WHILE (f # NIL) & (d.SameLock (fl, f.fl) # d.same) DO f := f.next END;
  113.   RETURN f
  114. END Search;
  115.  
  116.  
  117. PROCEDURE Unlink (f : File);
  118.  
  119.   VAR f0 : File;
  120.  
  121. BEGIN (* Unlink *)
  122.   IF root # NIL THEN
  123.     IF f = root THEN
  124.       root := root.next
  125.     ELSE
  126.       f0 := root;
  127.       WHILE (f0.next # NIL) & (f0.next # f) DO
  128.         f0 := f0.next
  129.       END;
  130.       IF f0.next = f THEN f0.next := f.next END;
  131.     END
  132.   END;
  133.   f.next := NIL
  134. END Unlink;
  135.  
  136.  
  137. PROCEDURE ReadBuf (f : File; buf : Buffer; pos : LONGINT);
  138.  
  139.   VAR res : LONGINT;
  140.  
  141. BEGIN (* ReadBuf *)
  142.   res := d.Seek (f.fh, pos, d.beginning);
  143.   IF res # -1 THEN
  144.     buf.lim := SHORT (d.Read (f^.fh, buf.data, SectorSize));
  145.     buf.apos := pos;
  146.     buf.mod := FALSE;
  147.   END
  148. END ReadBuf;
  149.  
  150.  
  151. PROCEDURE WriteBuf (f : File; buf : Buffer);
  152.  
  153.   VAR res : LONGINT;
  154.  
  155. BEGIN (* WriteBuf *)
  156.   (* ASSERT (buf # NIL, 137); *)
  157.   res := d.Seek (f.fh, buf.apos, d.beginning);
  158.   IF res # -1 THEN
  159.     res := d.Write (f.fh, buf.data, buf.lim);
  160.     IF res = buf.lim THEN
  161.       buf.mod := FALSE;
  162.     END
  163.   END
  164. END WriteBuf;
  165.  
  166.  
  167. PROCEDURE GetBuf (f : File; pos : LONGINT) : Buffer;
  168.  
  169.   VAR buf, last, next : Buffer;
  170.  
  171. BEGIN (* GetBuf *)
  172.   buf := f.firstbuf;
  173.   LOOP
  174.     IF buf.apos = pos THEN EXIT END;
  175.     IF buf.next = f.firstbuf THEN
  176.       last := buf;
  177.       IF f.nofbufs < MaxBufs THEN (* allocate new buffer *)
  178.         NEW (buf); INC (f.nofbufs);
  179.       ELSE (* take one of the buffers (assuming more than one) *)
  180.         buf := f.firstbuf; f.firstbuf := buf.next; last.next := buf.next;
  181.         IF buf.mod THEN WriteBuf (f, buf) END
  182.       END;
  183.       IF pos < f.firstbuf.apos THEN
  184.         f.firstbuf := buf
  185.       ELSIF pos < last.apos THEN
  186.         WHILE last.next.apos < pos DO last := last.next END;
  187.       END;
  188.       buf.next := last.next; last.next := buf;
  189.       buf.apos := pos; buf.lim := 0; buf.mod := FALSE;
  190.       IF pos < f.len THEN ReadBuf (f, buf, pos) END;
  191.       EXIT
  192.     END;
  193.     buf := buf.next
  194.   END; (* LOOP *)
  195.   RETURN buf;
  196. END GetBuf;
  197.  
  198.  
  199. PROCEDURE Unbuffer (f : File);
  200.  
  201.   VAR buf : Buffer;
  202.  
  203. BEGIN (* Unbuffer *)
  204.   buf := f.firstbuf;
  205.   REPEAT
  206.     IF buf.mod THEN WriteBuf (f, buf) END;
  207.     buf := buf.next
  208.   UNTIL buf = f.firstbuf
  209. END Unbuffer;
  210.  
  211.  
  212. PROCEDURE Delete * ( name : ARRAY OF CHAR; VAR res : INTEGER );
  213. <*$CopyArrays-*>
  214. BEGIN (* Delete *)
  215.   IF d.DeleteFile (name) THEN
  216.     res := 0
  217.   ELSE
  218.     res := SHORT (d.IoErr ());
  219.     IF res = d.objectNotFound THEN res := 0 END
  220.   END
  221. END Delete;
  222.  
  223.  
  224. PROCEDURE Rename * ( old, new : ARRAY OF CHAR; VAR res : INTEGER );
  225. <*$CopyArrays-*>
  226. BEGIN (* Rename *)
  227.   IF d.Rename (old, new) THEN res := 0
  228.   ELSE res := SHORT (d.IoErr ())
  229.   END
  230. END Rename;
  231.  
  232.  
  233. PROCEDURE Old * ( name : ARRAY OF CHAR ) : File;
  234.  
  235.   VAR
  236.     f : File; fl : d.FileLockPtr; fh : d.FileHandlePtr;
  237.     fib : d.FileInfoBlockPtr; len : LONGINT; buf : Buffer;
  238.  
  239. <*$CopyArrays-*>
  240. BEGIN (* Old *)
  241.   fl := d.Lock (name, d.sharedLock);
  242.   IF fl # NIL THEN
  243.     f := Search (fl);
  244.     IF f = NIL THEN
  245.       fh := d.Open (name, d.oldFile);
  246.       IF fh # NIL THEN
  247.         fib := d.AllocDosObjectTags (d.fib, NIL);
  248.         IF fib # NIL THEN
  249.           IF d.Examine (fl, fib^) THEN len := fib.size;
  250.           ELSE len := 0
  251.           END;
  252.           d.FreeDosObject (d.fib, fib);
  253.           NEW (f);
  254.           IF f # NIL THEN
  255.             NEW (buf);
  256.             IF buf # NIL THEN
  257.               buf.apos := 0; buf.next := buf; buf.mod := FALSE;
  258.               IF len > SectorSize THEN buf.lim := SectorSize
  259.               ELSE buf.lim := SHORT (len)
  260.               END;
  261.               f.len := len; f.firstbuf := buf; f.nofbufs := 1;
  262.               COPY (name, f.name); f.tempNo := 0;
  263.               f.fl := fl; f.fh := fh; f.pos := 0;
  264.               f.useCount := 0; f.next := root; root := f;
  265.               ReadBuf (f, buf, 0);
  266.               RETURN f
  267.             END;
  268.           END;
  269.         END;
  270.       END;
  271.       d.OldClose (fh)
  272.     END;
  273.     d.UnLock (fl)
  274.   END;
  275.   RETURN f
  276. END Old;
  277.  
  278.  
  279. PROCEDURE New * ( name : ARRAY OF CHAR ) : File;
  280.  
  281.   VAR
  282.     f : File; fl : d.FileLockPtr; fh : d.FileHandlePtr;
  283.     buf : Buffer; tempName : ARRAY 256 OF CHAR;
  284.  
  285. <*$CopyArrays-*>
  286. BEGIN (* New *)
  287.   REPEAT
  288.     IF tempNo < MAX (LONGINT) THEN INC (tempNo) ELSE tempNo := 1 END;
  289.     MakeName (name, tempNo, tempExt, tempName)
  290.   UNTIL ~du.FileExists (tempName);
  291.   fh := d.Open (tempName, d.newFile);
  292.   IF fh # NIL THEN
  293.     NEW (f);
  294.     IF f # NIL THEN
  295.       NEW (buf);
  296.       IF buf # NIL THEN
  297.         buf.apos := 0; buf.next := buf; buf.mod := TRUE;
  298.         buf.lim := 0;
  299.         f.len := 0; f.firstbuf := buf; f.nofbufs := 1;
  300.         COPY (name, f.name); f.tempNo := tempNo;
  301.         f.fl := d.Lock (tempName, d.sharedLock); f.fh := fh; f.pos := 0;
  302.         f.useCount := 0; f.next := root; root := f;
  303.         ReadBuf (f, buf, 0);
  304.         RETURN f
  305.       END
  306.     END
  307.   END;
  308.   d.OldClose (fh);
  309.   RETURN f
  310. END New;
  311.  
  312.  
  313. PROCEDURE Register * ( f : File );
  314.  
  315.   VAR tempName, bkpName : ARRAY 256 OF CHAR; res : INTEGER;
  316.  
  317. BEGIN (* Register *)
  318.   ASSERT (f # NIL, 137);
  319.   IF f.fh # NIL THEN
  320.     Unbuffer (f);
  321.     (* IF f.useCount <= 0 THEN *)
  322.       Unlink (f);
  323.       IF d.Close (f.fh) THEN
  324.         f.fh := NIL; d.UnLock (f.fl); f.fl := NIL;
  325.         IF f.tempNo # 0 THEN
  326.           MakeName (f.name, f.tempNo, tempExt, tempName);
  327.           IF f.name = "" THEN
  328.             Delete (tempName, res)
  329.           ELSE
  330.             MakeName (f.name, f.tempNo, bkpExt, bkpName);
  331.             Rename (f.name, bkpName, res);
  332.             IF res = 0 THEN
  333.               Rename (tempName, f.name, res);
  334.               IF res = 0 THEN Delete (bkpName, res) END
  335.             ELSIF res = d.objectNotFound THEN
  336.               Rename (tempName, f.name, res)
  337.             END
  338.           END
  339.         END
  340.       END
  341.     (* END *)
  342.   END
  343. END Register;
  344.  
  345.  
  346. PROCEDURE Close * ( f : File );
  347. BEGIN (* Close *)
  348.   ASSERT (f # NIL, 137);
  349.   IF f.fh # NIL THEN
  350.     Unbuffer (f);
  351.     (* IF f.useCount <= 0 THEN *)
  352.       Unlink (f);
  353.       IF d.Close (f.fh) THEN f.fh := NIL; d.UnLock (f.fl); f.fl := NIL END
  354.     (* END *)
  355.   END
  356. END Close;
  357.  
  358.  
  359. PROCEDURE Purge * ( f : File );
  360.  
  361.   VAR tempName : ARRAY 256 OF CHAR; res : INTEGER;
  362.  
  363. BEGIN (* Purge *)
  364.   ASSERT (f # NIL, 137);
  365.   IF f.fh # NIL THEN
  366.     Unbuffer (f);
  367.     IF d.SetFileSize (f.fh, 0, d.beginning) = 0 THEN f.pos := 0 END;
  368.     (* IF f.useCount <= 0 THEN *)
  369.       Unlink (f);
  370.       IF d.Close (f.fh) THEN f.fh := NIL; d.UnLock (f.fl); f.fl := NIL END;
  371.       IF f.tempNo # 0 THEN
  372.         MakeName (f.name, f.tempNo, tempExt, tempName);
  373.         Delete (tempName, res)
  374.       END
  375.     (* END *)
  376.   END
  377. END Purge;
  378.  
  379.  
  380. PROCEDURE Length * ( f : File ) : LONGINT;
  381.  
  382. BEGIN (* Length *)
  383.   ASSERT (f # NIL, 137); ASSERT (f.fh # NIL, 137);
  384.   RETURN f.len
  385. END Length;
  386.  
  387.  
  388. PROCEDURE GetDate * ( f : File; VAR time, day : LONGINT );
  389.  
  390.   VAR fib : d.FileInfoBlockPtr;
  391.  
  392. BEGIN (* GetDate *)
  393.   ASSERT (f # NIL, 137); ASSERT (f.fh # NIL, 137);
  394.   fib := d.AllocDosObjectTags (d.fib, NIL);
  395.   IF fib # NIL THEN
  396.     IF d.ExamineFH (f.fh, fib^) THEN
  397.       o.ADOS2OberonTime (fib.date, time, day);
  398.     END;
  399.     d.FreeDosObject (d.fib, fib)
  400.   END
  401. END GetDate;
  402.  
  403.  
  404. PROCEDURE Set * ( VAR r : Rider; f : File; pos : LONGINT );
  405.  
  406. BEGIN (* Set *)
  407.   (* IF (r.file # NIL) & (r.file # f) THEN DEC (r.file.useCount) END; *)
  408.   (* IF (f # NIL) & (f # r.file) THEN INC (f. useCount) END; *)
  409.   r.eof := FALSE; r.res := 0; r.file := f;
  410.   IF f # NIL THEN
  411.     IF pos < 0 THEN r.pos := 0; r.bpos := 0
  412.     ELSE r.bpos := SHORT (pos MOD SectorSize); r.pos := pos - r.bpos
  413.     END;
  414.     r.buf := f.firstbuf
  415.   END
  416. END Set;
  417.  
  418.  
  419. PROCEDURE Pos * ( VAR r : Rider ) : LONGINT;
  420. BEGIN (* Pos *)
  421.   RETURN r.pos + r.bpos
  422. END Pos;
  423.  
  424.  
  425. PROCEDURE Base * ( VAR r : Rider ) : File;
  426. BEGIN (* Base *)
  427.   RETURN r.file
  428. END Base;
  429.  
  430.  
  431. PROCEDURE Read * ( VAR r : Rider; VAR x : SYS.BYTE );
  432.  
  433.   VAR buf : Buffer;
  434.  
  435. BEGIN (* Read *)
  436.   ASSERT (r.file # NIL, 97);
  437.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  438.   IF r.bpos < r.buf.lim THEN
  439.     x := r.buf.data [r.bpos]; INC (r.bpos)
  440.   ELSIF (r.pos + SectorSize) < r.file.len THEN
  441.     INC (r.pos, SectorSize);
  442.     r.buf := GetBuf (r.file, r.pos);
  443.     x := r.buf.data [0]; r.bpos := 1
  444.   ELSE
  445.     x := 0X; r.eof := TRUE
  446.   END
  447. END Read;
  448.  
  449.  
  450. PROCEDURE ReadBytes * ( VAR r : Rider; VAR x : ARRAY OF SYS.BYTE;
  451.                           n : LONGINT );
  452.  
  453.   VAR src, dst, m : LONGINT;
  454.       buf : Buffer;
  455.  
  456. BEGIN (* ReadBytes *)
  457.   ASSERT (r.file # NIL, 137); ASSERT (r.file.fh # NIL, 137);
  458.   dst := SYS.VAL (LONGINT, SYS.ADR (x));
  459.   IF LEN (x) < n THEN HALT (25) END;
  460.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  461.   LOOP
  462.     IF n <= 0 THEN EXIT END;
  463.     src := SYS.VAL (LONGINT, SYS.ADR(r.buf.data));
  464.     INC (src, r.bpos); m := r.bpos + n;
  465.     IF m <= r.buf.lim THEN
  466.       SYS.MOVE (src, dst, n); r.bpos := SHORT (m); r.res := 0;
  467.       EXIT
  468.     ELSIF r.buf.lim = SectorSize THEN
  469.       m := r.buf.lim - r.bpos;
  470.       IF m > 0 THEN
  471.         SYS.MOVE (src, dst, m); INC (dst, m); DEC (n, m)
  472.       END;
  473.       IF r.pos < r.file.len THEN
  474.         INC (r.pos, SectorSize);
  475.         r.bpos := 0; r.buf := GetBuf (r.file, r.pos);
  476.       ELSE
  477.         r.res := n; r.eof := TRUE; EXIT
  478.       END;
  479.     ELSE
  480.       m := r.buf.lim - r.bpos;
  481.       IF m > 0 THEN
  482.         SYS.MOVE (src, dst, m); r.bpos := r.buf.lim
  483.       END;
  484.       r.res := n - m; r.eof := TRUE; EXIT
  485.     END;
  486.   END; (* LOOP *)
  487. END ReadBytes;
  488.  
  489.  
  490. <*$ < StackChk- IndexChk- *>
  491.  
  492. PROCEDURE SwapWord ( VAR w : ARRAY OF SYS.BYTE );
  493.  
  494.   VAR t : SYS.BYTE;
  495.  
  496. BEGIN (* SwapWord *)
  497.   t := w [0]; w [0] := w [1]; w [1] := t
  498. END SwapWord;
  499.  
  500.  
  501. PROCEDURE SwapLongword ( VAR l : ARRAY OF SYS.BYTE );
  502.  
  503.   VAR t : SYS.BYTE;
  504.  
  505. BEGIN (* SwapLongword *)
  506.   t := l [0]; l [0] := l [3]; l [3] := t;
  507.   t := l [1]; l [1] := l [2]; l [2] := t;
  508. END SwapLongword;
  509.  
  510. <*$ > *>
  511.  
  512.  
  513. PROCEDURE ReadInt * ( VAR r : Rider; VAR x : INTEGER );
  514.  
  515.   VAR i : INTEGER;
  516.  
  517. BEGIN (* ReadInt *)
  518.   ReadBytes (r, i, 2); SwapWord (i); x := i
  519. END ReadInt;
  520.  
  521.  
  522. PROCEDURE ReadLInt * ( VAR r : Rider; VAR x : LONGINT );
  523.  
  524.   VAR i : LONGINT;
  525.  
  526. BEGIN (* ReadLInt *)
  527.   ReadBytes (r, i, 4); SwapLongword (i); x := i
  528. END ReadLInt;
  529.  
  530.  
  531. PROCEDURE ReadReal * ( VAR r : Rider; VAR x : REAL );
  532.  
  533.   VAR y : REAL;
  534.  
  535. BEGIN (* ReadReal *)
  536.   ReadBytes (r, y, 4); SwapLongword (y); x := y
  537. END ReadReal;
  538.  
  539.  
  540. PROCEDURE ReadLReal * ( VAR r : Rider; VAR x : LONGREAL );
  541. BEGIN (* ReadLReal *)
  542.   HALT (99)
  543. END ReadLReal;
  544.  
  545.  
  546. PROCEDURE ReadNum * ( VAR r : Rider; VAR x : LONGINT );
  547.  
  548.   VAR s : SHORTINT; ch : CHAR; n : LONGINT;
  549.  
  550. BEGIN (* ReadNum *)
  551.   s := 0; n := 0; Read(r, ch);
  552.   WHILE ORD(ch) >= 128 DO
  553.     INC(n, ASH(ORD(ch) - 128, s)); INC(s, 7); Read(r, ch)
  554.   END;
  555.   x := n + ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s)
  556. END ReadNum;
  557.  
  558.  
  559. PROCEDURE ReadString * ( VAR r : Rider; VAR x : ARRAY OF CHAR );
  560.  
  561.   VAR ch : CHAR; i : INTEGER;
  562.  
  563. BEGIN (* ReadString *)
  564.   i := 0;
  565.   REPEAT
  566.     Read (r, ch); x [i] := ch; INC (i)
  567.   UNTIL ch = 0X
  568. END ReadString;
  569.  
  570.  
  571. PROCEDURE ReadSet * ( VAR r : Rider; VAR x : SET );
  572.  
  573.   VAR s : SET;
  574.  
  575. BEGIN (* ReadSet *)
  576.   ReadBytes (r, s, 4); SwapLongword (s); x := s
  577. END ReadSet;
  578.  
  579.  
  580. PROCEDURE ReadBool * ( VAR r : Rider; VAR x : BOOLEAN );
  581.  
  582.   VAR i : SHORTINT;
  583.  
  584. BEGIN (* ReadBool *)
  585.   Read (r, i); x := (i # 0)
  586. END ReadBool;
  587.  
  588.  
  589. PROCEDURE Write * ( VAR r : Rider; x : SYS.BYTE );
  590.  
  591.   VAR f : File; buf : Buffer;
  592.  
  593. BEGIN (* Write *)
  594.   ASSERT (r.file # NIL, 137); ASSERT (r.file.fh # NIL, 137);
  595.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  596.   IF r.bpos >= r.buf.lim THEN
  597.     IF r.bpos < SectorSize THEN
  598.       INC (r.buf.lim); INC (r.file.len)
  599.     ELSE
  600.       f := r.file; INC (r.pos, SectorSize);
  601.       r.buf := GetBuf (f, r.pos);
  602.       IF r.pos >= f.len THEN r.buf.lim := 1; f.len := r.pos END;
  603.       r.bpos := 0
  604.     END
  605.   END;
  606.   r.buf.data [r.bpos] := x; INC (r.bpos); r.buf.mod := TRUE
  607. END Write;
  608.  
  609.  
  610. PROCEDURE WriteBytes * ( VAR r : Rider; VAR x : ARRAY OF SYS.BYTE;
  611.                           n : LONGINT );
  612.  
  613.   VAR src, dst, m : LONGINT; f : File; buf : Buffer;
  614.  
  615. BEGIN (* WriteBytes *)
  616.   ASSERT (r.file # NIL, 137); ASSERT (r.file.fh # NIL, 137);
  617.   src := SYS.VAL (LONGINT, SYS.ADR (x));
  618.   IF LEN (x) < n THEN HALT (25) END;
  619.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  620.   LOOP
  621.     IF n <= 0 THEN EXIT END;
  622.     r.buf.mod := TRUE;
  623.     dst := SYS.VAL (LONGINT, SYS.ADR(r.buf.data)); INC (dst, r.bpos);
  624.     m := r.bpos + n;
  625.     IF m <= r.buf.lim THEN
  626.       SYS.MOVE (src, dst, n); r.bpos := SHORT (m); EXIT
  627.     ELSIF m <= SectorSize THEN
  628.       SYS.MOVE (src, dst, n); r.bpos := SHORT (m);
  629.       INC (r.file.len, n); r.buf.lim := SHORT (m); EXIT
  630.     ELSE
  631.       m := SectorSize - r.bpos;
  632.       IF m > 0 THEN
  633.         SYS.MOVE (src, dst, m); INC (src, m); DEC (n, m);
  634.         INC (r.buf.lim, SHORT (m))
  635.       END;
  636.       f := r.file; INC (r.pos, SectorSize);
  637.       r.bpos := 0; r.buf := GetBuf (f, r.pos);
  638.       IF r.pos >= f.len THEN r.buf.lim := 0; f.len := r.pos END;
  639.     END;
  640.   END; (* LOOP *)
  641. END WriteBytes;
  642.  
  643.  
  644. PROCEDURE WriteInt * ( VAR r : Rider; x : INTEGER );
  645. BEGIN (* WriteInt *)
  646.   SwapWord (x); WriteBytes (r, x, 2);
  647. END WriteInt;
  648.  
  649.  
  650. PROCEDURE WriteLInt * ( VAR r : Rider; x : LONGINT );
  651. BEGIN (* WriteLInt *)
  652.   SwapLongword (x); WriteBytes (r, x, 4);
  653. END WriteLInt;
  654.  
  655.  
  656. PROCEDURE WriteReal * ( VAR r : Rider; x : REAL );
  657. BEGIN (* WriteReal *)
  658.   SwapLongword (x); WriteBytes (r, x, 4);
  659. END WriteReal;
  660.  
  661.  
  662. PROCEDURE WriteLReal * ( VAR r : Rider; x : LONGREAL );
  663. BEGIN (* WriteLReal *)
  664.   HALT (99)
  665. END WriteLReal;
  666.  
  667.  
  668. PROCEDURE WriteNum * ( VAR r : Rider; x : LONGINT );
  669. BEGIN (* WriteNum *)
  670.   WHILE (x < -64) OR (x > 63) DO
  671.     Write(r, CHR(x MOD 128 + 128)); x := x DIV 128
  672.   END;
  673.   Write(r, CHR(x MOD 128))
  674. END WriteNum;
  675.  
  676.  
  677. PROCEDURE WriteString * ( VAR r : Rider; x : ARRAY OF CHAR );
  678. <*$CopyArrays-*>
  679. BEGIN (* WriteString *)
  680.   WriteBytes (r, x, str.Length (x)); Write (r, 0X)
  681. END WriteString;
  682.  
  683.  
  684. PROCEDURE WriteSet * ( VAR r : Rider; x : SET );
  685. BEGIN (* WriteSet *)
  686.   SwapLongword (x); WriteBytes (r, x, 4);
  687. END WriteSet;
  688.  
  689.  
  690. PROCEDURE WriteBool * ( VAR r : Rider; x : BOOLEAN );
  691.  
  692.   VAR i : SHORTINT;
  693.  
  694. BEGIN (* WriteBool *)
  695.   IF x THEN i := 1 ELSE i := 0 END; Write (r, i)
  696. END WriteBool;
  697.  
  698.  
  699. PROCEDURE* CloseFiles ( VAR rc : LONGINT );
  700.  
  701. BEGIN (* CloseFiles *)
  702.   WHILE root # NIL DO
  703.     IF root.fh # NIL THEN
  704.       Unbuffer (root);
  705.       IF d.Close (root.fh) THEN END;
  706.       d.UnLock (root.fl);
  707.     END;
  708.     root := root.next
  709.   END;
  710. END CloseFiles;
  711.  
  712.  
  713. BEGIN (* Files *)
  714.   root := NIL; GetTempNo; Kernel.SetCleanup (CloseFiles);
  715. END Files.
  716.